/*
    COMP9517 Computer Vision, Semester 2, 2011 - University of New South Wales
   ============================================================================
   |   Group .  | Christian Mostegel & Dong Back Kim                          |
   ============================================================================
 */

#ifndef __CAMERA_H__
#define __CAMERA_H__

#include <qstring.h>

#include "Point3D.h"

class Camera
{

//----------------------------------------------------------------------------
// Constructor and Destructor
//----------------------------------------------------------------------------

public:

        /// default constructor
        Camera();

        /// default destructor
        virtual ~Camera();

//----------------------------------------------------------------------------
// Camera Identity
//----------------------------------------------------------------------------

private:

        QString _camera_filename;

        /// camera unique id
        int _camera_id;

        /// camera name
        QString _camera_name;

public:

        inline void setFilename(const QString & name) { _camera_filename = name; }
        inline QString getFilename() const { return _camera_filename; }

        /// sets camera's identity
        inline void setCameraIdentity(int uniqueID, const QString & name)
        {
                _camera_id = uniqueID;
                _camera_name = name;
        }

        /// gets camera's id number (this supposes to be a unique value)
        inline int getCameraID() const
        {
                return _camera_id;
        }

        /// gets camear's name
        inline const QString & getCameraName() const
        {
                return _camera_name;
        }

//----------------------------------------------------------------------------
// Projection Configuration
//----------------------------------------------------------------------------

private:

        /// camera fovy
        float _camera_fovy;

        /// camera ratio
        float _camera_ratio;

public:

        /// sets camera fovy
        inline void setCameraFovy(float fovy)
        {
                _camera_fovy = fovy;
        }

        /// sets camera ratio
        inline void setCameraRatio(float ratio)
        {
                _camera_ratio = ratio;
        }

        /// sets camera fovy
        inline float getCameraFovy() const
        {
                return _camera_fovy;
        }

        /// sets camera ratio
        inline float getCameraRatio() const
        {
                return _camera_ratio;
        }

//----------------------------------------------------------------------------
// Camera geometry
//----------------------------------------------------------------------------

private:

        //* projMatrix – 3x4 input projection matrix P.
        //* cameraMatrix – Output 3x3 camera matrix K.
        //* rotMatrix – Output 3x3 external rotation matrix R.


        //* transVect – Output 4x1 translation vector T.
        /// camera position
        Vector3D _camera_position_vector;

        //* rotMatrZ – Optional 3x3 rotation matrix around z-axis.
        /// camera direction vector
        Vector3D _camera_direction_vector;

        //* rotMatrY – Optional 3x3 rotation matrix around y-axis.
        /// camera up vector
        Vector3D _camera_up_vector;

        //* rotMatrX – Optional 3x3 rotation matrix around x-axis.
        /// camera right vector
        Vector3D _camera_right_vector;

        //* eulerAngles – Optional three-element vector containing three Euler angles of rotation.
        /// camera rotation vector(?)
        Vector3D _camera_rotation_vector;

public:


        inline void setCameraPosition(const Vector3D & v)		{ _camera_position_vector = v; }
        inline void setCameraDirection(const Vector3D & v)		{ _camera_direction_vector = v; }
        inline void setCameraUpVector(const Vector3D & v)		{ _camera_up_vector = v; }
        inline void setCameraRightVector(const Vector3D & v)	{ _camera_right_vector = v; }
        inline void setCameraRotationVector(const Vector3D & v)	{ _camera_rotation_vector = v; }


        inline const Vector3D &	getCameraPosition() const		{ return _camera_position_vector; }
        inline const Vector3D &	getCameraDirection() const		{ return _camera_direction_vector; }
        inline const Vector3D &	getCameraUpVector() const		{ return _camera_up_vector; }
        inline const Vector3D &	getCameraRightVector() const	{ return _camera_right_vector; }
        inline const Vector3D &	getCameraRotationVector() const	{ return _camera_rotation_vector; }

//----------------------------------------------------------------------------
// Basic Camera Maneuvers
//----------------------------------------------------------------------------

public:

        void rotateX			(float degree);
        void rotateY			(float degree);
        void rotateZ			(float degree);

        void forwardTranslate           (float distance);
        void upTranslate		(float distance);
        void rightTranslate		(float distance);

//----------------------------------------------------------------------------
// Camera Smooth Transition
//----------------------------------------------------------------------------

private:

        /// smooth transition option flag
        bool _use_smooth_transition;

        /// smooth transition length
        int _transition_length;

        /// smooth transition step indicator
        int _transition_step;

        /// camera position
        Vector3D _goal_position_vector;

        /// camera direction vector
        Vector3D _goal_direction_vector;

        /// camera up vector
        Vector3D _goal_up_vector;

        /// camera right vector
        Vector3D _goal_right_vector;

        /// camera rotation vector(?)
        Vector3D _goal_rotation_vector;

        /// initial position vector
        Vector3D _initial_position_vector;

        /// initial direction vector
        Vector3D _initial_direction_vector;

        /// initial up vector
        Vector3D _initial_up_vector;

        /// initial right vector
        Vector3D _initial_right_vector;

        /// initial rotation vector
        Vector3D _initial_rotation_vector;

protected:

        void resetTransition();
        void updateInterpolation();

public:

        inline void EnableSmoothTransition(bool flag)           { _use_smooth_transition = flag; }
        inline bool IsUsingSmoothTransition() const		{ return _use_smooth_transition; }

        inline void SetTransitionLength(int frames)
        {
                if ( frames < 1 )	_transition_length = 1; // NaN Protection
                else			_transition_length = frames;
        }

        void update();
        void copyGeometryFrom(const Camera & targetCamera);

};

#endif // __CAMERA_H__
